<?php

namespace App\Models\Traits;

use App\Models\Search;
use App\Models\Product;
use App\Models\ProductSku;
use App\Models\ProductSlide;
use App\Models\ProductImage;
use Illuminate\Support\Facades\Log;
use Rainsens\Dinglog\Facades\Dinglog;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Redis;
use Illuminate\Database\Eloquent\Builder;

trait ProductCacheTrait
{
	public static function initProductsCache()
	{
		Redis::del(self::sProductsCacheKey());
		Dinglog::text("============================== Normal Products Cache Syncing...");
		Product::initAllProductsCache();
		Dinglog::text("============================== Normal Products Cache Synced...");
	}

	public static function initAllProductsCache()
	{
		self::sale()->where('is_gold_storm',false)->each(function (Product $product) {
			$product->addToCache();
			Log::info("Normal product: {$product->id} synced to cache");
		});
	}

	public static function sCategoryProductsCacheKey($cid)
	{
		return "category_{$cid}_products";
	}

	public static function sGoldBeanProductsCacheKey()
	{
		return "gold_bean_products";
	}

	public static function sTop100ProductsCacheKey()
	{
		return "top_100_products";
	}

	public static function sIntegralProductsCacheKey()
	{
		return "integral_products";
	}

	public static function sSearchProductsCacheKey()
	{
		return "search_products";
	}

	public static function sProductsCacheKey()
	{
		return "normal_products";
	}

	public static function sCacheKey($id)
	{
		return "normal_product_{$id}";
	}

	public static function sGetCache($id)
	{
		if (! Cache::has(self::sCacheKey($id))) {
			if ($product = Product::find($id)) {
				$product->fresh()->addToCache();
			}
		}
		return Cache::get(self::sCacheKey($id));
	}

	public static function randomProducts($cacheKey)
	{
		if (Redis::sCard($cacheKey) <= 0) return collect();

		$items = collect();
		$randomIds = Redis::sRandMember($cacheKey, 10);

		foreach ($randomIds as $id) {
			$product = Cache::get(self::sCacheKey($id));
			$items->push($product);
		}

		return $items;
	}

	public static function sGetGoldBeanProductsCache()
	{
		return self::randomProducts(self::sGoldBeanProductsCacheKey());
	}

	public static function sGetTop100ProductsCache()
	{
		return self::randomProducts(self::sTop100ProductsCacheKey());
	}

	public static function sGetIntegralProductsCache()
	{
		return self::randomProducts(self::sIntegralProductsCacheKey());
	}

	public static function sGetCategoryProductsCache($cid)
	{
		return self::randomProducts(self::sCategoryProductsCacheKey($cid));
	}

	public static function sGetProducts()
	{
		$cid = request('cid', null);
		$isIntegral = request('is_integral', null);
		$isGoldBean = request('is_gold_bean', null);

		$appVersion = request("app_version");
		

		if ($isGoldBean) {
			return self::sGetGoldBeanProductsCache();
		} elseif ($appVersion == cs("app")->pending_android_version) {
			return self::sGetIntegralProductsCache();
		} elseif ($cid) {
			return self::sGetCategoryProductsCache($cid);
		} else {
			return self::randomProducts(self::sProductsCacheKey());
		}
	}

	public static function sSearchFromCache($keyword)
	{
		$ids = Product::select('id')
			->where('is_sale', true)
			->where(function (Builder $query) use ($keyword) {
				$query->where('title', 'like', "%$keyword%")->orWhere('title_long', 'like', "%$keyword%");
			})->inRandomOrder()->take(10)->get();

		if ($ids->isEmpty()) return collect();

		$products = collect();

		foreach ($ids as $id) {
			$products->push(Product::sGetCache($id['id']));
		}

		Search::recordSearchToCache($keyword);

		return $products;
	}



	/*==================================================================================================================*/



	public function cacheKey()
	{
		return "normal_product_{$this->id}";
	}



	public function cacheSkus()
	{
		$skus = collect();

		$this->skus()->each(function (ProductSku $sku) use ($skus) {
			$extract = [
				'id' => $sku->id,
				'product_id' => $sku->product_id,
				'name' => (string)$sku->name,
				'pic_url' => img_path($sku->pic),
				'attr_value' => $sku->attr_value,
				'attr_value_index' => $sku->attr_value_index,
				'attr_value_index_array' => $sku->getAttrValueIndexArray(),
				'price' => $sku->price,
				'price_vip' => $sku->price_vip,
				'stock' => (int)$sku->stock,
			];
			$skus->push($extract);
		});

		return $skus;
	}

	public function cacheSlides()
	{
		$slides = collect();

		$this->slides()->each(function (ProductSlide $slide) use ($slides) {
			$extract = [
				'id' => (int)$slide->id,
				'product_id' => (int)$slide->product_id,
				'slide_url' => img_path($slide->slide),
			];
			$slides->push($extract);
		});

		return $slides;
	}

	public function cacheImages()
	{
		$images = collect();

		$this->images()->each(function (ProductImage $image) use ($images) {
			$extract = [
				'id' => (int)$image->id,
				'product_id' => (int)$image->product_id,
				'image_url' => img_path($image->image),
			];
			$images->push($extract);
		});

		return $images;
	}

	public function cacheFields()
	{
		return [
			'id' => $this->id,
			'category_id' => $this->category_id,
			'title' => $this->title,
			'description' => $this->description,
			'recommendation' => $this->recommendation,
			'cover_url' => $this->cover_url,
			'price_lowest' => $this->price_lowest,
			'price_market' => $this->price_market,
			'sold_count' => (int)$this->sold_count,
			'comment_count' => (int)$this->comment_count,
			'comment_favor_rate' => (int)$this->comment_favor_rate,
			'is_gold_storm' => $this->is_gold_storm,
			'is_gold_bean' => $this->is_gold_bean,
			'skus' => $this->cacheSkus(),
			'slides' => $this->cacheSlides(),
			'images' => $this->cacheImages(),
			'command_user_id' => $this->commandUser ? $this->commandUser->id : 0,
			'command_user_name' => $this->commandUser? $this->commandUser->name : '',
			'command_link' => $this->command_link,
		];
	}

	public function addToCache()
	{
		$data = $this->cacheFields();

		Cache::put($this->cacheKey(), $data);

		Redis::sAdd(self::sProductsCacheKey(), $this->id);
		Redis::sAdd(self::sCategoryProductsCacheKey($this->category_id), $this->id);

		if ($this->is_gold_bean) {
			Redis::sAdd(self::sGoldBeanProductsCacheKey(), $this->id);
		}
		if ($this->is_integral) {
			Redis::sAdd(self::sIntegralProductsCacheKey(), $this->id);
		}

		if ($this->category) {
			$this->category->addToCache();
		}

		Log::debug("Normal product: {$this->id} added to cache");
	}

	public function delFromCache()
	{
		Cache::forget($this->cacheKey());

		Redis::sRem(self::sCategoryProductsCacheKey($this->category_id), $this->id);
		Redis::sRem(self::sGoldBeanProductsCacheKey(), $this->id);
		Redis::sRem(self::sIntegralProductsCacheKey(), $this->id);
		Redis::sRem(self::sProductsCacheKey(), $this->id);
	}
}
